﻿using System;
using System.Collections.Generic;
using System.Threading;
using Microsoft.FxCop.Sdk;

namespace LINQtoFxCop.Core
{
  
  /// <summary>
  /// This class is an addition to the FxCop analysis engine. This is needed to be able to perform analysis queries on application level instead of just node level
  /// </summary>
  internal class AnalysisController
  {
    private DateTime _analysisTimeStamp; //time stamp of last analysis of a rule - used to determine when an analysis run has finished
    private bool _analysisIsInProgress; //semaphore for keeping track of whether an analysis run is in progress
    private readonly Timer _timer; //the timer object for invoking "ticks"
    private readonly object _analysisIsFinishedLockObject = new object(); //locking object for thread safety
    private readonly IDictionary<string, ProblemCollection> _problems; //analysis result problem collection - should be emptied between each complete analysis run

    public static readonly AnalysisController Instance = new AnalysisController(); //public handle for insance of this class (singleton)

    private AnalysisController()
    {
      TargetCodebase = new TargetCodebase();
      Reporting = new ReportingService();
      _problems = new Dictionary<string, ProblemCollection>();
      _timer = new Timer(Tick);
      _timer.Change(0, 200);
      Init();
    }

    private void Tick(object state)
    {
      lock (_analysisIsFinishedLockObject)
      {
        if (!AnalysisIsFinished())
          return;

        Reporting.WriteToDisk(_problems); //is analysis has just finished, then write report to disc
        Init(); //initialize analysis controller state for a new run
      }
    }

    private bool AnalysisIsFinished()
    {
      return DateTime.Now > _analysisTimeStamp + new TimeSpan(0, 0, 0, 3) && _analysisIsInProgress;
    }
    internal void RuleAnalysisStarting()
    {
      //if reporting is pending, then application analysis has already begun
      if (_analysisIsInProgress)
        return;
      Init();
    }
    internal void RuleAnalysisFinishing()
    {
      //if reporting is pending, then application analysis has already begun
      if (_analysisIsInProgress)
        return;
      Application = TargetCodebase.Build(); //prepare (build) target codebase for rule querying
    }
    internal void AddContent(ModuleNode module)
    {
      TargetCodebase.AddContent(module);
    }
    internal void AddProblems(string ruleName, ProblemCollection problems)
    {
      _problems.Add(ruleName, problems);
      _analysisIsInProgress = true;
      _analysisTimeStamp = DateTime.Now;
    }

    private void Init()
    {
      TargetCodebase.Init();
      _problems.Clear();
      _analysisTimeStamp = DateTime.Now;
      _analysisIsInProgress = false;
    }
    private TargetCodebase TargetCodebase
    { get; set; }
    internal ApplicationNode Application
    { get; private set; }
    private ReportingService Reporting
    { get; set; }
  }
}

